#include "common/elements/user.h"

#include "common/log/log.h"

#include "data_user.h"

namespace Database
{

DataUser::DataUser(Elements::Element* element)
{
    setElement(element);
}

DataUser::DataUser(std::shared_ptr<Elements::Element> element)
{
    m_element = element;
}

DataUser::DataUser(sqlite::database& database, unsigned id)
{
    fromDatabase(database, id);
}

DataElement* DataUser::clone() const
{
    if (m_element)
        return new DataUser(m_element->clone());

    return nullptr;
}

DataElement* DataUser::wrap(Elements::Element* element) const
{
    return new DataUser(element);
}

void DataUser::toDatabase(sqlite::database& database)
{
    const auto element = std::dynamic_pointer_cast<Elements::User>(m_element);
    if (nullptr == element)
        return;

    if (0 == element->id())
    {
        const auto sqlStr = "INSERT INTO User "
                            "( login "
                            ", firstName "
                            ", middleName "
                            ", lastName "
                            ", email "
                            ", passwordHash "
                            ", needChangePassword "
                            ", isBlocked "
                            ", uiLang "
                            ") VALUES (?,?,?,?,?,?,?,?,?);";
        database
            << sqlStr
            << element->login()
            << element->firstName()
            << element->middleName()
            << element->lastName()
            << element->email()
            << element->passwordHash()
            << element->needChangePassword()
            << element->isBlocked()
            << element->uiLang();
        element->setId(lastAddedId(database));
        return;
    }

    const auto sqlStr = "INSERT OR REPLACE INTO User "
                        "( id "
                        ", login "
                        ", firstName "
                        ", middleName "
                        ", lastName "
                        ", email "
                        ", passwordHash "
                        ", needChangePassword "
                        ", isBlocked "
                        ", uiLang "
                        ") VALUES (?,?,?,?,?,?,?,?,?,?);";
    database
        << sqlStr
        << element->id()
        << element->login()
        << element->firstName()
        << element->middleName()
        << element->lastName()
        << element->email()
        << element->passwordHash()
        << element->needChangePassword()
        << element->isBlocked()
        << element->uiLang();
}

void DataUser::fromDatabase(sqlite::database& database, unsigned id)
{
    if (nullptr == m_element)
        m_element.reset(new Elements::User());

    const auto element = std::dynamic_pointer_cast<Elements::User>(m_element);

    const auto sqlStr = "SELECT "
                        "  id "
                        ", login "
                        ", firstName "
                        ", middleName "
                        ", lastName "
                        ", email "
                        ", passwordHash "
                        ", needChangePassword "
                        ", isBlocked "
                        ", uiLang "
                        "FROM User WHERE id = ?;";
    database << sqlStr << id >>
        [element](
            unsigned id,
            std::string login,
            std::string firstName,
            std::string middleName,
            std::string lastName,
            std::string email,
            std::string passwordHash,
            bool needChangePassword,
            bool isBlocked,
            std::string uiLang
        )
    {
        element->setId(id);
        element->setLogin(login);
        element->setFirstName(firstName);
        element->setMiddleName(middleName);
        element->setLastName(lastName);
        element->setEmail(email);
        element->setPasswordHash(passwordHash);
        element->setNeedChangePassword(needChangePassword);
        element->setIsBlocked(isBlocked);
        element->setUiLang(uiLang);
    };
}

std::vector<Elements::Element*> DataUser::fromDatabaseElements(
    sqlite::database& database,
    std::vector<unsigned> ids
) const
{
    const auto sqlStr = "SELECT "
                        "  id "
                        ", login "
                        ", firstName "
                        ", middleName "
                        ", lastName "
                        ", email "
                        ", passwordHash "
                        ", needChangePassword "
                        ", isBlocked "
                        ", uiLang "
                        "FROM User WHERE id in ("
        + questionMarks(ids.size())
        + ")";

    auto query = database << sqlStr;
    for (auto id : ids)
        query << id;

    std::vector<Elements::Element*> result;
    query >>
        [&result](
            unsigned id,
            std::string login,
            std::string firstName,
            std::string middleName,
            std::string lastName,
            std::string email,
            std::string passwordHash,
            bool needChangePassword,
            bool isBlocked,
            std::string uiLang
        )
    {
        auto element = new Elements::User();
        element->setId(id);
        element->setLogin(login);
        element->setFirstName(firstName);
        element->setMiddleName(middleName);
        element->setLastName(lastName);
        element->setEmail(email);
        element->setPasswordHash(passwordHash);
        element->setNeedChangePassword(needChangePassword);
        element->setIsBlocked(isBlocked);
        element->setUiLang(uiLang);
        result.push_back(element);
    };
    return result;
}

// Получение идентификаторов ---------------------------------------------------

std::vector<unsigned> DataUser::ids(
    sqlite::database& database
)
{
    std::vector<unsigned> result;
    database << "SELECT id FROM User;"
        >> [&result](unsigned id)
    {
        result.emplace_back(id);
    };
    return result;
}

// Удаление --------------------------------------------------------------------

void DataUser::removeOne(
    sqlite::database& database,
    unsigned id
)
{
    std::vector<unsigned> ids = { id };
    remove(database, ids);
}

void DataUser::remove(
    sqlite::database& database,
    std::vector<unsigned> ids
)
{
    const auto sqlStr = "DELETE FROM User WHERE id in ("
        + questionMarks(ids.size())
        + ")";

    auto query = database << sqlStr;
    for (auto id : ids)
        query << id;

    query.execute();
    query.reset();
}

} // namespace Elements
